#include "Display.h"


Display::Display(): _display_width(SCREEN_WIDTH), 
					_display_height(SCREEN_HEIGHT),
					_display(0), 
					_event_queue(0)
{
	try
	{
	initialiseAllegroComponents();
	allocateAllegroResources();
	_game_box = al_create_bitmap(GAME_BOX_SIZE,GAME_BOX_SIZE);
	_score_box = al_create_bitmap(SCORE_BOX_SIZE_X,GAME_BOX_SIZE);
	}
	catch (string errr)
	{
		cout<<(errr);
	}
}

void Display::initialiseAllegroComponents() const
{
	
	//! initialise Allegro itself
	if(!al_init()) throw "ERROR INITIALISING";

	// initialise primitives addon (for drawing shapes)
	if(!al_init_primitives_addon()) throw "PRIMITIVES_ADDON_ERROR";	

	// install the keyboard
	if(!al_install_keyboard()) throw "KEYBOARD_ERROR";
	

}

void Display::allocateAllegroResources()
{

	//!create the display
	_display = al_create_display(_display_width, _display_height);
	if(!_display) throw "DISPLAY_ERROR";
	
	//!create an event queue and register event sources
	_event_queue = al_create_event_queue();
	if(!_event_queue)
	{
		//cleanup already allocated resources
		al_destroy_display(_display);
		throw "EVENT_QUEUE_ERROR";
	}

	// load font
	al_init_font_addon();
	al_init_ttf_addon();
	//_font18 = al_load_font("arial.ttf", 18, 0);
	//_font24 = al_load_font("arial.ttf", 24, 0);
	_font60 = al_load_font("arial.ttf", 40, 0);
	_font24 = al_load_font("arial.ttf", 24, 0);
	_font32 = al_load_font("arial.ttf", 32, 0);
	//if (!_font18 || !_font24 || _font60)
	if(!_font60 || !_font24)
	{
		// cleanup already allocated resources
		al_destroy_event_queue(_event_queue);
		al_destroy_display(_display);
		throw "FONT_SETUP_ERROR";
	}

	//!Create the event timer
	_timer = al_create_timer(1.0 / FPS);
	if(!_timer)	{ 
		//cleanup already allocated resources
		al_destroy_display(_display);
		al_destroy_event_queue(_event_queue);
		throw "TIMER_SETUP_ERROR";	
	}

	//!Add the Keyboard as an event
	al_register_event_source(_event_queue, al_get_keyboard_event_source());

	//!Add the display buttons as events
	al_register_event_source(_event_queue, al_get_display_event_source(_display));

	//!Add the timer as an event
	al_register_event_source(_event_queue, al_get_timer_event_source(_timer));

	
}

void Display::startTimer()
{
	al_start_timer(_timer);
}


void Display::update()
{
	drawBoxesToScreen();	
	al_flip_display();
}

void Display::clearBuffer()
{
	al_set_target_bitmap(_game_box);
	al_clear_to_color(BLACK);

	al_set_target_bitmap(_score_box);
	al_clear_to_color(BLACK);

	al_set_target_bitmap(al_get_backbuffer(_display));
	al_clear_to_color(BLACK);
}


void Display::drawBoxesToScreen()
{
	al_set_target_bitmap(al_get_backbuffer(_display));
	al_draw_bitmap(_game_box, GAME_BOX_START_X, GAME_BOX_START_Y,0);
	al_draw_bitmap(_score_box, SCORE_BOX_START_X, SCORE_BOX_START_Y,0);
}

void Display::drawScoreBox(int score, int lives, int high_score, int level)
{
	al_set_target_bitmap(_score_box);
	int y = 75;

	string message = "DIG GUG";
	al_draw_text(_font60, BLUE,0 , 0, 0, message.c_str()); 
	al_draw_line(0, y, SCORE_BOX_SIZE_X, y, al_map_rgb(127,255,0), 0);
	//-----------------------------------------------------
	y+=20;
	message = "Move: Arrow Keys";
	al_draw_text(_font24, BROWN, 0, 0 +y, 0, message.c_str()); 
	
	y+=35;
	message = "Shoot: Space Bar";
	al_draw_text(_font24, BROWN, 0, 0 +y, 0, message.c_str()); 
	
	y+=35;
	message = "Pause: P";
	al_draw_text(_font24, BROWN, 0, 0 +y, 0, message.c_str()); 

	y+=35;
	message = "Exit: Esc";
	al_draw_text(_font24, BROWN, 0, 0 +y, 0, message.c_str()); 
	//---------------------------------------------------------
	y+=45;
	al_draw_line(0 , y,  SCORE_BOX_SIZE_X, y, al_map_rgb(127,255,0), 0);
	
	y+=20;
	al_draw_textf(_font32, RED, 0, 0 + y , 0,"Score: %i", score);
	y+=45;
	al_draw_textf(_font24, BROWN, 0,0 + y, 0,"High Score: %i", high_score);
	y+=45;
	al_draw_line(0, y, SCORE_BOX_SIZE_X, y, al_map_rgb(127,255,0), 0);
	y+=20;
	al_draw_textf(_font32, YELLOW, 0, y, 0,"Level: %i", level);
	y+=50;
	al_draw_line(0, 0 + y, SCORE_BOX_SIZE_X, y, al_map_rgb(127,255,0), 0);
	y+=20;
	al_draw_textf(_font32, BLUE, 0,0 + y, 0,"Lives:");
	y+=50;

	for(int i = 1; i <= lives; i++)
	{
		al_draw_filled_circle(-15 + i*40, y, 15,YELLOW);
		al_draw_filled_circle(-15+ i*40, y, 13,GREEN);
	}
}
Display::~Display()
{
	// clean up memory allocated for the event_queue and display   
	al_destroy_event_queue(_event_queue);
	al_destroy_display(_display);
}

void display_setup_error_message( string &message)
{
	al_show_native_message_box(NULL, NULL, NULL, message.c_str(), NULL, ALLEGRO_MESSAGEBOX_ERROR);
}


void Display::drawAsGrid(vector <vector <Movable_type>> map) const
{
		al_set_target_bitmap(_game_box);
		ALLEGRO_COLOR COLOUR = BLACK; 
		for(int x = 0; x != GAME_GRID_ELEMENTS; x++)
		{
			for(int y = 0; y != GAME_GRID_ELEMENTS; y++)
			{
				
				switch(map.at(x).at(y))
				{
				case DIGDUG:		COLOUR = YELLOW; break;
				case MONSTER:		COLOUR = RED; break;
				case SAND:			COLOUR = BROWN; break;
				case PROJECTILE:	COLOUR = WHITE; break;
				default:			COLOUR = BLACK; break;
				}
				al_draw_filled_rectangle(	x*PIXEL_RATIO,  y*PIXEL_RATIO, 
											x*PIXEL_RATIO+5,  y*PIXEL_RATIO+5, COLOUR);
			}
		}
}

//! Draws the SAND bitmaps to the screen
void Display::drawMap(Map& map) const
{
	ALLEGRO_BITMAP* bitmap = map.bitmap();

	al_set_target_bitmap(_game_box);
	float sand_w = al_get_bitmap_width(bitmap);
	float sand_h = al_get_bitmap_height(bitmap);

	for(int x = 0; x < GAME_GRID_ELEMENTS; x++)
	{
		for(int y = 0; y < GAME_GRID_ELEMENTS; y++)
		{
			Point xy(x,y);

			if(map.positionType(xy)==SAND)
			{
				float fade =  (50.0-float(y))/50.0;
				al_draw_tinted_scaled_bitmap( bitmap, al_map_rgba_f(1,fade,1,1), 0, 0, sand_w, sand_h, 
									x*PIXEL_RATIO, y*PIXEL_RATIO, 
									PIXEL_RATIO, PIXEL_RATIO, 0);	
			}
		}
	}
}

void Display::drawDigdug(Digdug &digdug) const
{
	drawScaledBitmap(digdug.location(), digdug.radius(),0, digdug.bitmap());
}

void Display::drawMonsters( vector<Monster> &monsters)const
{
	for(int i = 0; i != monsters.size(); i++)
	{
		if(!monsters.at(i).isGhost())
			drawScaledBitmap(monsters.at(i).location(), monsters.at(i).radius(),monsters.at(i).blowUpSize()*0.2, monsters.at(i).bitmap());
		else
		{
			ALLEGRO_BITMAP* bmap = monsters.at(i).ghostBitmap();
			ALLEGRO_BITMAP* temp_bitmap = al_create_bitmap( al_get_bitmap_width(bmap), al_get_bitmap_height(bmap));;
			al_set_target_bitmap(temp_bitmap);
			al_draw_tinted_bitmap(bmap,  al_map_rgba_f(1, 1, 1, 0.3), 0,0,0);
			drawScaledBitmap(monsters.at(i).location(), monsters.at(i).radius(),0, temp_bitmap);
		}
	}
}

//Actually draws the bitmap to the _game_box bitmap
void Display::drawScaledBitmap(Point location, int radius,int scale,  ALLEGRO_BITMAP *bitmap) const
{
	al_set_target_bitmap(_game_box);
	float x = location.x() ;
	float y = location.y() ;
	float size = radius*2 + 1; 
	
	float height = al_get_bitmap_height(bitmap);
	float width = al_get_bitmap_width(bitmap);
	
	//Used as it draws as dx, dy centre
	al_draw_scaled_rotated_bitmap(	bitmap, 
									width/2, height/2, 
									x*PIXEL_RATIO +PIXEL_RATIO/2, y*PIXEL_RATIO +PIXEL_RATIO/2, 
									size*PIXEL_RATIO/width*(1+scale), size*PIXEL_RATIO/height*(1+scale),0,0); 
}



//! Projecile drawing is a bit more complicated as it has to go from digdug onwards.
void Display::drawProjectile(Projectile &projectile, Digdug &digdug) const
{
	if(!projectile.isShooting())
		return; 

	int delta_x = delta(projectile.direction()).at(0);
	int delta_y = delta(projectile.direction()).at(1);
	
	//The end point is at the end of the projectile
	float x_end = projectile.location().x();// + projectile.radius()*delta_x;
	float y_end = projectile.location().y();// + projectile.radius()*delta_y;

	//The start point is at digdug
	float x_start = digdug.location().x() + digdug.radius()*delta_x;
	float y_start = digdug.location().y() + digdug.radius()*delta_y;


	float x_center = (x_start+x_end)/2;
	float y_center = (y_start+y_end)/2;

	float x_scale = abs(x_start-x_end)/(projectile.radius()*2 +1)*0.8 + abs(delta_y);
	float y_scale = abs(y_start-y_end)/(projectile.radius()*2 +1)*0.8 + abs(delta_x);

	float height = al_get_bitmap_height(projectile.bitmap());
	float width = al_get_bitmap_width(projectile.bitmap());
	
	ALLEGRO_BITMAP* temp_bitmap = al_create_bitmap(width,height);
	al_set_target_bitmap(temp_bitmap);
	al_draw_rotated_bitmap(	projectile.bitmap(),  
									width/2, height/2, 
									width/2, height/2, 
									directionToAngle(projectile.direction()) , 0); 	

	al_set_target_bitmap(_game_box);
	al_draw_scaled_rotated_bitmap(	temp_bitmap,  
									width/2, height/2, 
									x_center*PIXEL_RATIO, y_center*PIXEL_RATIO, 
									x_scale, y_scale, 0 , 0); 		
}

ALLEGRO_EVENT_QUEUE* Display::event_queue()
{
	return _event_queue;
}

void Display::drawMessage(string message, string colour)
{
	al_set_target_bitmap(al_get_backbuffer(_display));
	string message2 = "Press Esc to Exit, Enter to Play Again";
	al_clear_to_color(al_map_rgb(0,0,0));
	al_draw_text(_font60, al_color_name(colour.c_str()), SCREEN_WIDTH/2, SCREEN_HEIGHT/2, ALLEGRO_ALIGN_CENTRE, message.c_str());
	al_draw_text(_font32, BLUE, SCREEN_WIDTH/2, SCREEN_HEIGHT/2 + 70, ALLEGRO_ALIGN_CENTRE, message2.c_str());
	al_flip_display();
}

int Display::showNativeDialogMessageQuestion(char const *title, char const *text)
{
	int answer = al_show_native_message_box( _display, title, "Question", text,NULL,  ALLEGRO_MESSAGEBOX_YES_NO);
	return answer;
}


void Display::showNativeDialogMessageOK(char const *title, char const *heading, char const *text)
{
	al_show_native_message_box( _display, title, "Option", text, 0,0);
}
